package com.surrey.p2p.model;

import java.net.Socket;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;

/**
 * Class to represent a CANNode in the Peer to Peer Network
 * 
 * @author Vedika Dalmia
 * 
 */
public class CANNode extends P2PNode {

	/**
	 * The zone that the CAN Node owns
	 */
	private CANZone zone;
	/**
	 * Socket to be used later to connect with other nodes
	 */
	private Socket s;
	/**
	 * List of neighbours of the node
	 */
	private List<CANNode> neighbours;
	/**
	 * Key-value pairs stored in the zone of that node
	 */
	private Hashtable<Point, String> data;

	/**
	 * Parameterized constructor to create a new Node
	 * 
	 * @param ipAddress
	 * @param zone
	 * @param neighbours
	 * @param data
	 */
	public CANNode(String ipAddress, CANZone zone, List<CANNode> neighbours, Hashtable<Point, String> data) {
		// TODO remove once join is implemented
		super(ipAddress);
		this.zone = zone;
		this.neighbours = neighbours;
		this.data = data;
	}

	/**
	 * Create a dummy node with just an address
	 * 
	 * @param ipAddress
	 */
	public CANNode(String ipAddress) {
		super(ipAddress);
		// TODO Auto-generated constructor stub
	}

	public CANZone getZone() {
		return zone;
	}

	public List<CANNode> getNeighbours() {
		return neighbours;
	}

	public void setNeighbours(List<CANNode> neighbours) {
		//this.neighbours = (ArrayList<CANNode>) neighbours;
		this.neighbours = neighbours;
	}
	
	public void finishRouting(){
		this.setChanged();
        this.notifyObservers("routing complete");
	}

	public CANNode lookup(Point p, HopCount count) {
		
		//System.out.println("In Node " + this.getAddress() + " " +count);
		if (this.zone.inZone(p)) {
			
			return this;
		} else {
			CANNode result = null;
			CANNode lookupNextIn = null;
			double minDistance = Double.MAX_VALUE;
			Iterator<CANNode> i = neighbours.iterator();
			while (result == null && i.hasNext()) {
				CANNode c = (CANNode) i.next();
				if (c.getZone().inZone(p)) {				
					result = c;
					//System.out.println("Sending routing update to network");
					String s="route " + result.getAddress().toString();
					this.setChanged();
		            this.notifyObservers(s);
				}
				double distance = p.distance(c.getZone().getCentre());
				if (distance < minDistance) {
					minDistance = distance;
					lookupNextIn = c;
				}
			}
			if (result == null) {
				count.addHop();
				//System.out.println("Sending routing update to network");
				String s="route " + lookupNextIn.getAddress().toString();
				this.setChanged();
	            this.notifyObservers(s);
				result = lookupNextIn.lookup(p,count);
			}
			
			return result;
		}
	}
}
